package com.kuizii.generator.util.generator;

import com.google.common.base.CaseFormat;
import com.kuizii.generator.domain.entity.TableEntity;
import com.kuizii.generator.util.DateUtils;
import com.kuizii.generator.util.RRException;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 生成API模块代码
 * </p>
 *
 * @author nuanyang
 * Email
 * created by 2018/6/20
 */
public class GeneratorApiUtils {

    /**
     * 获取模板
     *
     * @return
     */
    private static List<String> getTemplates() {
        List<String> templates = new ArrayList<>();
        templates.add("templates/api/pom/apipom.xml.vm");
        //   templates.add("templates/api/service/service-package-info.java.vm");
//        templates.add("templates/api/dto/dto-package-info.java.vm");
//        templates.add("templates/api/fallback/fallback-package-info.java.vm");
        return templates;
    }


    /**
     * 生成对应的代码
     *
     * @param zip
     */
    public static void generatorCode(ZipOutputStream zip) {
        Configuration config = GeneratorConfig.getConfig();
        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);
        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("author", config.getString("author"));
        map.put("email", config.getString("email"));
        map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
        map.put("moduleType", GeneratorConfig.MODULE_API);
        map.put("artifactId", GeneratorConfig.getProjectNameNotSlash(GeneratorConfig.MODULE_API));
        map.put("description", config.getString("description"));
        map.put("version", config.getString("version"));
        map.put("moduleName", GeneratorConfig.getModuleName().replace("-", "."));
        map.put("package", config.getString("package"));
        map.put("rpc-type", config.getString("rpc-type"));
        map.put("parentArtifactId", GeneratorConfig.getModuleParent() + GeneratorConfig.getModuleName());
        map.put("endPoint", GeneratorConfig.getEndPoint());
        VelocityContext context = new VelocityContext(map);
        List<String> templates = getTemplates();
        try {
            for (String template :
                    templates) {
                //渲染模板
                StringWriter sw = new StringWriter();
                Template tpl = Velocity.getTemplate(template, "UTF-8");
                tpl.merge(context, sw);
                //添加到zip
                zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, ""))));
                IOUtils.write(sw.toString(), zip, "UTF-8");
                IOUtils.closeQuietly(sw);
                zip.closeEntry();
            }
        } catch (IOException e) {
            throw new RRException("渲染模板失败", e);
        }

    }

    /**
     * 自动生成代码
     *
     * @param table
     * @param columns
     * @param zip
     */
    public static void generatorCode(Map<String, String> table,
                                     List<Map<String, String>> columns, ZipOutputStream zip) {
        Configuration config = GeneratorConfig.getConfig();
        boolean hasBigDecimal = false;
        boolean hasDate = false;
        //表信息
        TableEntity tableEntity = new TableEntity();
        tableEntity.setTableName(table.get("tableName"));
        tableEntity.setComments(table.get("tableComment"));

        //表名转换成Java类名
        String className = tableToJava(tableEntity.getTableName(), config.getString("tablePrefix"));
        if(isOracle()){
            className= CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, className);
        }else{
            className = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, className);
        }
        tableEntity.setClassName(className);
        tableEntity.setClassname(StringUtils.uncapitalize(className));


        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);
        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("tableName", tableEntity.getTableName());
        map.put("className", className );
        map.put("lowerClassName",WordUtils.uncapitalize(className));
        map.put("routeClassName",className);
        map.put("rpc-type", config.getString("rpc-type"));
        map.put("pathName", tableEntity.getClassname().toLowerCase());
        map.put("mainPath", GeneratorConfig.getProjectPackage(GeneratorConfig.MODULE_API));
        map.put("moduleName", GeneratorConfig.getModuleName().replace("-", "."));
        map.put("author", config.getString("author"));
        map.put("email", config.getString("email"));
        map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
        map.put("artifactId", GeneratorConfig.getProjectNameNotSlash(GeneratorConfig.MODULE_API));
        map.put("description", config.getString("description"));
        map.put("version", config.getString("version"));
        map.put("moduleType", GeneratorConfig.MODULE_CORE);
        map.put("package", config.getString("package"));
        map.put("endPoint", GeneratorConfig.getEndPoint());
        VelocityContext context = new VelocityContext(map);
        List<String> templates = new ArrayList<>();

        templates.add("templates/api/service/service-package-info.java.vm");
        for (String template :
                templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);
            try {
                //添加到zip
                zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, className))));
                IOUtils.write(sw.toString(), zip, "UTF-8");
                IOUtils.closeQuietly(sw);
                zip.closeEntry();
            } catch (IOException e) {
                throw new RRException("渲染模板失败，表名：" + tableEntity.getTableName(), e);
            }
        }


    }

    /**
     * 获取模板对应的名称
     *
     * @param template
     * @return
     */
    private static String getFileName(String template, String className) {
        if (template.contains("apipom.xml.vm")) {
            return GeneratorConfig.getProjectName(GeneratorConfig.MODULE_API) + "pom.xml";
        }
        if (template.contains("service-package-info.java.vm")) {
            return GeneratorConfig.getProjectJavaRoute(GeneratorConfig.MODULE_API) + className + "Service.java";
        }
        if (template.contains("dto-package-info.java.vm")) {
            return GeneratorConfig.getProjectJavaRoute(GeneratorConfig.MODULE_API) + "dto" + File.separator + "package-info.java";
        }
        if (template.contains("fallback-package-info.java.vm")) {
            return GeneratorConfig.getProjectJavaRoute(GeneratorConfig.MODULE_API) + "fallback" + File.separator + "package-info.java";
        }

        return null;
    }

    /**
     * 表名转换成Java类名
     */
    private static String tableToJava(String tableName, String tablePrefix) {
        if (StringUtils.isNotBlank(tablePrefix)) {
            tableName = tableName.replace(tablePrefix, "");
        }
        tableName = columnToJava(tableName);

        return tableName;
    }


    /**
     * 列名转换成Java属性名
     */
    private static String columnToJava(String columnName) {
        Configuration config = GeneratorConfig.getConfig();
        if ("mysql".equals(config.getString("sql-type"))) {
            if (columnName.length() > 3) {
                //如果数据库是is开头的，去除is，转成成java类型
                if (columnName.startsWith("is_")) {
                    columnName = columnName.substring(3);
                }
            }

            if (columnName.contains("_")) {
                return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
            }else{
                if (columnName.length() > 1) {
                    columnName = String.format("%s%s",
                            StringUtils.lowerCase(columnName.substring(0, 1)),
                            columnName.substring(1));
                }
                return columnName;
            }
        } else {
            if (columnName.toLowerCase().startsWith("is")) {
                columnName = columnName.substring(2);
            }
            if (columnName.length() > 1) {
                columnName = String.format("%s%s",
                        StringUtils.lowerCase(columnName.substring(0, 1)),
                        columnName.substring(1));
            }
            return columnName;
        }

    }
    public static boolean isOracle() {
        Configuration config = GeneratorConfig.getConfig();
        return "oracle".equals(config.getString("sql-type"));
    }
}
